﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.StyleCop;
using Microsoft.StyleCop.CSharp;
using SPStyleCop.Rules.SPQueryRuleItems;

namespace SPStyleCop.Rules
{
    [SourceAnalyzer(typeof(CsParser))]
    public sealed class SPQueryRules : SourceAnalyzer
    {
        private AnalyzerRegistry _analyzerRegistry;

        /// <summary>
        /// Initializes a new instance of the <see cref="SPQueryRules"/> class.
        /// </summary>
        public SPQueryRules()
        {

        }

        public override void AnalyzeDocument(CodeDocument document)
        {
            CsDocument csDocument = (CsDocument) document;            
            if (document == null) throw new ArgumentNullException("document");

            RegisterRuleItems();
            this._analyzerRegistry.RuleAnalyzers.ForEach(analyzer => analyzer.Initialize(this));
            this._analyzerRegistry.RuleAnalyzers.ForEach(analyzer => analyzer.VisitBeforeAnalysis(document));

            CsDocument csharpDocument = (CsDocument)document;

            csharpDocument.WalkDocument(this.VisitElement,
                new CodeWalkerStatementVisitor<object>(this.VisitStatement),
                new CodeWalkerExpressionVisitor<object>(this.VisitExpression),
                new CodeWalkerQueryClauseVisitor<object>(this.VisitQueryClause));

            csharpDocument.Tokens.ForEach(token =>
                this._analyzerRegistry.RuleAnalyzers.ForEach(analyzer =>
                    analyzer.VisitToken(document, token)));

            this._analyzerRegistry.RuleAnalyzers.ForEach(analyzer => analyzer.VisitAfterAnalysis(document));

            
        }

        private void RegisterRuleItems()
        {
            this._analyzerRegistry = ServiceLocator.GetService<AnalyzerRegistry>();
            if (this._analyzerRegistry == null)
            {
                this._analyzerRegistry = new AnalyzerRegistry();
                ServiceLocator.RegisterService<AnalyzerRegistry>(this._analyzerRegistry);
            }

            this._analyzerRegistry.AddAnalyzer<ViewFieldRuleItem>(new ViewFieldRuleItem());
        }

        private bool VisitElement(CsElement element, CsElement parentElement, object context)
        {
            this._analyzerRegistry.RuleAnalyzers.ForEach(analyzer => analyzer.VisitElement(element, parentElement, context));

            return true;
        }

        private bool VisitStatement(Statement statement, Expression parentExpression, Statement parentStatement,
                                           CsElement parentElement, object context)
        {
            this._analyzerRegistry.RuleAnalyzers.ForEach(
                analyzer => analyzer.VisitStatement(statement, parentExpression, parentStatement, parentElement, context));

            return true;
        }

        private bool VisitExpression(Expression expression, Expression parentExpression, Statement parentStatement,
                                            CsElement parentElement, object context)
        {
            this._analyzerRegistry.RuleAnalyzers.ForEach(
                analyzer => analyzer.VisitExpression(expression, parentExpression, parentStatement, parentElement, context));

            return true;
        }

        private bool VisitQueryClause(QueryClause clause, QueryClause parentClause, Expression parentExpression,
                                             Statement parentStatement, CsElement parentElement, object context)
        {
            this._analyzerRegistry.RuleAnalyzers.ForEach(
                analyzer => analyzer.VisitQueryClause(clause, parentClause, parentExpression, parentStatement, parentElement, context));

            return true;
        }

       
    }
}
